package org.grayrabbit.cms.action.content;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Result;
import org.grayrabbit.cms.action.common.SimpleAction;
import org.grayrabbit.cms.constant.DictionaryStaticValues;
import org.grayrabbit.cms.constant.ConstantEnum.ContentTypes;
import org.grayrabbit.cms.content.base.AbstractExportMission;
import org.grayrabbit.cms.content.base.BaseMission;
import org.grayrabbit.cms.content.base.Common;
import org.grayrabbit.cms.content.base.CountDto;
import org.grayrabbit.cms.content.base.ResultDto;
import org.grayrabbit.cms.content.exp.XMLExportMission;
import org.grayrabbit.cms.content.imp.ContentImport;
import org.grayrabbit.cms.content.imp.XMLImportMission;
import org.grayrabbit.cms.entity.Category;
import org.grayrabbit.cms.entity.Content;
import org.grayrabbit.cms.entity.Dictionary;
import org.grayrabbit.cms.service.content.ContentService;
import org.grayrabbit.cms.util.FilePathSptUtil;
import org.grayrabbit.cms.util.FileUtil;
import org.grayrabbit.cms.util.ZipUtil;
import org.grayrabbit.cms.vo.content.ContentBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;

import org.grayrabbit.dao.util.Page;

/**
 *		ContentFileAction.java
 *		@Author      hasau   
 *		@CreateTime  2012-2-3  下午1:20:11	
 **/
@Controller
@Scope("prototype")
public class ContentFileAction extends SimpleAction{
  
	private static final long serialVersionUID = 1L;
	private static final int BUFFER_SIZE = 100*1024; //单次吞吐量 100K
	private static final int UPLOAD_MAX_SIZE = 100*1024*1024; //最大100M
	private static final Logger LOGGER =LoggerFactory.getLogger(ContentFileAction.class);
	
	private String categoryId;
	private String contentIds;
	private String fileType;
	private File upload;
	private String uploadFileName;
	private ResultDto resultDto;
	private CountDto countDto;
	private InputStream inputStream;
	private String fileName;
	private ContentBean content;
	private List<Dictionary> dicContentType;
	private ContentTypes[] contentTypes = ContentTypes.values(); 
	
	@Autowired
	@Qualifier("contentServiceImpl")
	private ContentService contentService;
	
	
	@Action(value="content-exp-imp")
	public String expImp(){
		dicContentType = dictionaryService.getDictionaryListByTypeCode(DictionaryStaticValues.CONTENT_STATUS);	 
		return "content-exp-imp";
	}
	
	@Action(value="content-file-import",results={
			@Result(name="impresult",location="content-result.jsp" )
	})
	public String contentImoprt(){ 
		InputStream in = null;
		OutputStream out = null;
		String msg = null;
		String suffix = null;
		if(StringUtils.isBlank(categoryId)) {
			this.addActionError("请选择导入的目的栏目");
			return "impresult";
		}
		//上传文件合法性判断 
		if(uploadFileName.endsWith(Common.POINT)){
			msg = "文件没有后缀名";
		}else{
			int index = uploadFileName.lastIndexOf(Common.POINT);
			if(index > -1){
				suffix = uploadFileName.substring(index+1,uploadFileName.length());
				if(Common.XML.equalsIgnoreCase(suffix) || Common.ZIP.equalsIgnoreCase(suffix)){
					// doc 的导入扩展等待…………
				}else{
					msg = "本功能暂时只支持 XML、ZIP格式的文件";
				}
			}else{
				msg = "文件没有后缀名";
			}
		}
		
		if(upload.length() > UPLOAD_MAX_SIZE){
			msg = "上传文件超过限额 100M" ; 
		}
		if(StringUtils.isNotBlank(msg)){
			addActionError(msg);
			return "impresult";
		} 
		countDto = new CountDto(0,0,0,0,0);
		resultDto = new ResultDto(0,0,false);
		File desFile = null;
		String unZipPath = null;
		try {
			String des= FilePathSptUtil.UPLOAD_ROOT_PATH+Common.SPT+Common.CONTENT; 
			File pFile= new File(des);
			if(!pFile.exists()){
				pFile.mkdirs();
			}
			String newname = getCurrentAdminId()+System.currentTimeMillis();			
			unZipPath = des+Common.SPT+newname;
			des = des+Common.SPT+newname+Common.POINT+suffix;
			desFile = new File(des);
			//文件上传开始 
			in = new BufferedInputStream(new FileInputStream(upload), BUFFER_SIZE);
			out = new BufferedOutputStream(new FileOutputStream(desFile), BUFFER_SIZE);
			
			byte[] buffer = new byte[BUFFER_SIZE];
			int l;
			while ((l=in.read(buffer))>0){
				out.write(buffer, 0, l);
				out.flush(); 
			}	
			resultDto.setFlag(true);
		} catch (FileNotFoundException e) {
			LOGGER.error("上传文件不存在",e); 
			this.addActionError("上传读取文件异常");
			resultDto.setFlag(false);
			return "impresult";
		} catch (IOException e) {
			LOGGER.error("上传读取文件异常",e); 
			this.addActionError("上传读取文件异常");
			resultDto.setFlag(false);
			return "impresult";
		} finally{
			try {
				out.close();
				in.close();
				System.out.println("山");
			} catch (IOException e) {
				LOGGER.error("输出输入流关闭异常",e);  
			}
		} 
		//导入 执行
		String key = getRequest().getSession().getId()+System.currentTimeMillis();		
		importDoc(desFile,unZipPath,categoryId,getCurrentSiteId(),suffix,key);
		if(resultDto.getExistNum() > 0){
		this.addActionMessage(resultDto.getExistNum()+" 个内容已经存在，或者导入异常 ");
		}
		return "impresult";
	}

	private void importDoc(File des, String unZipPath, String categoryId,String siteId,
			String suffix,String key) {
		if(Common.DOC.equalsIgnoreCase(suffix)){
			//TODO  doc 导入
			this.addActionError("暂不支持DOC格式的导入"); 
		}else if(Common.XML.equalsIgnoreCase(suffix)){
			Content c = ContentImport.singleXMLImport(des,categoryId,siteId);
			contentService.save2(c);
		}else if(Common.ZIP.equalsIgnoreCase(suffix)){
			// zip导入
			try {
				List<String> list = ContentImport.zipExtract(des, unZipPath);
				int totalNum = list.size();
				int pageSize = 10;
				int totalPage = 0;
				int currentpage = 1;
				if(totalNum%pageSize == 0){
					totalPage = totalNum/pageSize;
				}else{
					totalPage = totalNum/pageSize+1;
				}
				countDto = new CountDto(0,0,0,0,0);				
				resultDto.setTotalNum(totalNum);
				CountDto dto = null;
				BaseMission.addMapItem(key, new CountDto(0,totalPage,0,0,0));
				int lastIndex = 0;
				while(totalPage+1 > currentpage){
					if(currentpage == totalPage){
						lastIndex = list.size();
					}else{
						lastIndex = pageSize*currentpage;
					} 
					List<String> listPage =  new ArrayList<String>();
					for(int k = pageSize*(currentpage-1);k<lastIndex ;k++){
						listPage.add(list.get(k));
					} 
					
					XMLImportMission importMission = 
							new XMLImportMission(listPage,key,siteId,categoryId,contentService);
					importMission.importContents();
					currentpage++;
				}
				
				while(true){
					dto = (CountDto)BaseMission.getMapItem(key);
					if(dto.getMissionLeftNum() < 1){
						resultDto.setOveredNum(dto.getHaveDoneNum());
						resultDto.setTotalNum(totalNum);
						resultDto.setExistNum(dto.getExistOrErrorNum());
						break;
					}
				} 
			}catch (Exception e) {
				this.addActionError("导入异常");
				LOGGER.error("导入异常", e);
			}finally{
				FileUtil.delFile(des.getAbsolutePath());
				FileUtil.delFolder(unZipPath);
			}			
		} 
	}

	@Action(value="content-file-export",results={
			@Result(name="impresult",location="content-result.jsp" ) 
	})
	public String contentExoprt(){
		String parentName = getCurrentAdminId()+System.currentTimeMillis();
		String key = getRequest().getSession().getId()+System.currentTimeMillis();
		BaseMission.addMapItem(key, new CountDto(0,0,0,0,0));
		resultDto = new ResultDto(0,0,false); 
		if(StringUtils.isBlank(categoryId)){
			//按选定的内容导出
			this.addActionError("暂不支持DOC格式的导出"); 			
		}else{
			//按选定的栏目导出
			if(Common.DOC.equalsIgnoreCase(fileType)){
				this.addActionError("暂不支持DOC格式的导出");
			}else {
				// 导出 XML
				boolean f = exportDoc(categoryId,parentName,key);
				if(!f) {
					this.addActionError("没有内容可以导出,或者导出异常");
					return "impresult"; 
				}
				String fname = null;
				try {
					fileName = parentName+Common.POINT+Common.ZIP;
					fname = FilePathSptUtil.UPLOAD_ROOT_PATH+Common.SPT+Common.CONTENT
							+Common.SPT +fileName;
					inputStream= new FileInputStream(new File(fname));
					return "download";
				} catch (FileNotFoundException e) { 
					this.addActionError("下载异常");
					FileUtil.delFile(fname);
					LOGGER.error("下载异常", e);
				}
			}			
		}		 
		return "impresult";
	}
	
	private boolean exportDoc(String categoryId,String parentName,String key){
		boolean flag = false;
		Page<Content> page = new Page<Content>(MAX_PAGE_NUM,true);
		Category category = new Category();
		category.setCategoryId(categoryId);		 
		contentService.list(page, content);
		long totalPage = page.getTotalPages();
		countDto = new CountDto(0,0,0,0,0);
		if(totalPage == 0) return flag;
		int pageNum = page.getPageNo();		
		resultDto.setTotalNum(page.getTotal());		 
		CountDto dto =  null; 
		while(totalPage+1 > pageNum){
			List<Content> list = page.getResult(); 
			// 导出 任务
			AbstractExportMission mission = new XMLExportMission(list,parentName,key);
			mission.exportContents();
			while(true){ 
				dto = (CountDto)(BaseMission.getMapItem(key));
				if(dto.getMissionLeftNum()< 1){
					pageNum++;
					page.setPageNo(pageNum);
					contentService.list(page, content); 
					break;
				}
			}
		} 
		dto = (CountDto)(BaseMission.getMapItem(key));			
		setCountDto(dto);
		resultDto.setOveredNum(dto.getHaveDoneNum());
		BaseMission.removeItem(key);
		
		// 导出完毕 压缩  
		String des = null;
		while (true){
			if(dto.getItemTotalNum()+1> page.getTotal()){
				String src = null;
				if(dto.getHaveDoneNum() == 0) return flag; 
				//压缩 
				src = FilePathSptUtil.UPLOAD_ROOT_PATH+Common.SPT+Common.CONTENT
						+Common.SPT+parentName;
				des= src+Common.POINT+Common.ZIP;
				try {
					ZipUtil.createZip(src, des);
					File file = new File(des);
					if(file.exists()) flag = true; 
				} catch (Exception e) {					 
					FileUtil.delFile(des);
					LOGGER.error("压缩异常", e); 
				} finally{
					resultDto.setFlag(flag);
					FileUtil.delFolder(src);
				}
				break;
			} 
		}  
		// TODO 删除 ： 创建删除文件的 任务 定时 删除 创建N天的文件 （需另外处理）
		return flag; 
	}

	public File getUpload() {
		return upload;
	}

	public void setUpload(File upload) {
		this.upload = upload;
	}

	public String getUploadFileName() {
		return uploadFileName;
	}

	public void setUploadFileName(String uploadFileName) {
		this.uploadFileName = uploadFileName;
	}

	public String getContentIds() {
		return contentIds;
	}

	public void setContentIds(String contentIds) {
		this.contentIds = contentIds;
	}

	public String getFileType() {
		return fileType;
	}

	public void setFileType(String fileType) {
		this.fileType = fileType;
	}

	public String getCategoryId() {
		return categoryId;
	}

	public void setCategoryId(String categoryId) {
		this.categoryId = categoryId;
	}

	public ResultDto getResultDto() {
		return resultDto;
	}

	public void setResultDto(ResultDto resultDto) {
		this.resultDto = resultDto;
	} 
	public InputStream getInputStream() {
		return inputStream;
	}

	public void setInputStream(InputStream inputStream) {
		this.inputStream = inputStream;
	}

	public String getFileName() {
		return fileName;
	}

	public void setFileName(String fileName) {
		this.fileName = fileName;
	}

	public CountDto getCountDto() {
		return countDto;
	}

	public void setCountDto(CountDto countDto) {
		this.countDto = countDto;
	}

	public List<Dictionary> getDicContentType() {
		return dicContentType;
	}

	public void setDicContentType(List<Dictionary> dicContentType) {
		this.dicContentType = dicContentType;
	}

	public ContentTypes[] getContentTypes() {
		return contentTypes;
	}

	public void setContentTypes(ContentTypes[] contentTypes) {
		this.contentTypes = contentTypes;
	}

	public ContentBean getContent() {
		return content;
	}

	public void setContent(ContentBean content) {
		this.content = content;
	}
}
